#include "ExperimentDirectorThread.h"

#include <QtCore/QFile>
#include <QtCore/QTextStream>


namespace jcrada {

    ExperimentDirectorThread::ExperimentDirectorThread(std::vector<ExperimentThread*>& experiments,
            BulletSimulator& simulator) : SimulationThread(simulator),
    _experiments(&experiments),
    _next_experiment(0),
    _lock(new QReadWriteLock(QReadWriteLock::Recursive)) {

    }

    ExperimentDirectorThread::~ExperimentDirectorThread() {

    }

    void ExperimentDirectorThread::iterate() {
        ExperimentThread* experiment = getCurrentExperiment();
        if (!experiment) {
            emit message("All experiments conducted.");
            setStopped(true);
            return;
        }

        QObject::connect(experiment, SIGNAL(message(const QString&)),
                this, SLOT(experimentMessage(const QString&)), Qt::DirectConnection);
        experiment->setSimulationSpeed(getSimulationSpeed());
        experiment->play();
        experiment->wait();
        if (!isStopped()) {
            saveToFile(experiment->getExperiment());
        }
        QObject::disconnect(experiment, SIGNAL(message(const QString&)),
                this, SLOT(experimentMessage(const QString&)));
        if (!isStopped()) {
            ++_next_experiment;
        }
    }

    void ExperimentDirectorThread::saveToFile(const Experiment& experiment) {
        std::string stats_basename = DEF_EXPERIMENTS + "stats/" + experiment._description;
        QFile file(QString(nextFileAvailable(stats_basename, "stats", "xml").c_str()));
        if (!file.open(QFile::WriteOnly)) {
            emit message("Error: could not append to " + file.fileName());
        } else {
            QDomDocument doc;
            experiment.statisticsToXml(doc);
            QTextStream stream(&file);
            stream << doc.toString();
            file.close();
        }

        std::string best_basename = DEF_EXPERIMENTS + "best/" + experiment._description;
        file.setFileName(QString(nextFileAvailable(best_basename, "best", "xml").c_str()));
        if (!file.open(QFile::WriteOnly)) {
            emit message("Error: could not append to " + file.fileName());
        } else {
            QDomDocument doc;
            experiment.bestCreaturesToXml(doc);
            QTextStream stream(&file);
            stream << doc.toString();
            file.close();
        }

        std::string evolved_basename = DEF_EXPERIMENTS + "evolved/" + experiment._description;
        file.setFileName(QString(nextFileAvailable(evolved_basename, "evolved", "xml").c_str()));
        if (!file.open(QFile::WriteOnly)) {
            emit message("Error: could not append to " + file.fileName());
        } else {
            QDomDocument doc;
            experiment.evolvedCreaturesToXml(doc);
            QTextStream stream(&file);
            stream << doc.toString();
            file.close();
        }

//        std::string pso_basename = DEF_EXPERIMENTS + "pso/" + experiment._description;
//        file.setFileName(QString(nextFileAvailable(pso_basename, "pso", "xml").c_str()));
//        if (!file.open(QFile::WriteOnly)) {
//            emit message("Error: could not append to " + file.fileName());
//        } else {
//            QDomDocument doc;
//            experiment.particlesToXml(doc);
//            QTextStream stream(&file);
//            stream << doc.toString();
//            file.close();
//        }
    }

    std::string ExperimentDirectorThread::nextFileAvailable(const std::string& basename,
            const std::string& middlename, const std::string& extension) {
        std::string filename = basename + "." + middlename + "." + extension;
        QFile file(QString(filename.c_str()));
        if (!file.exists()) {
            return filename;
        }
        int append = 0;
        do {
            filename = basename + " " + TO_STRING(++append) + "." + middlename + "." + extension;
            file.setFileName(QString(filename.c_str()));
        } while (file.exists());
        return filename;
    }
}
